using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class VTAAPass : VScriptableRenderPass
{
   
   
    internal RenderTextureDescriptor descriptor { get; set; }
    RenderTexture []historyBuffer;
    private RenderTexture historyRead;
    private RenderTexture historyWrite;
    private RenderTargetIdentifier _source;
    private RenderTargetIdentifier _depth;
    private RenderTargetIdentifier _target;
    RenderTextureDescriptor m_Descriptor;
    private Material _material;
    private float _BlendAlpha;
    private bool m_ResetHistory;
    
    Matrix4x4 previousGPUVPMatrix;
    Vector2 previousJitterOffset;
    public VTAAPass(RenderPassEvent renderPassEvent):base(renderPassEvent)
    {
        _material = new Material(Shader.Find("Hidden/VPR/TAA"));
        _BlendAlpha = 0.05f;
        historyBuffer = new RenderTexture[2];
 
    }

    ~VTAAPass()
    {
        if (historyBuffer[0])
        {
            RenderTexture.ReleaseTemporary(historyBuffer[0]);
        }

        if (historyBuffer[1])
        {
            RenderTexture.ReleaseTemporary(historyBuffer[1]);
        }
    }
    public void SetUp(ScriptableRenderContext context, ref VRenderingData renderingData)
    {
        _BlendAlpha = renderingData.postFXSettings.TAA.BlendAlpha;
        var camera = renderingData.cameraData.camera;
        var mat=camera.previousViewProjectionMatrix;
        m_Descriptor = renderingData.cameraData.cameraTargetDescriptor;
        uint FrameCount = renderingData.FrameCount;
        if (FrameCount == 0)
            previousGPUVPMatrix = SaveGPUViewProjection(renderingData);
        uint readindex = FrameCount % 2;
        uint writeindex = (FrameCount+1) % 2;
        historyRead = historyBuffer[readindex];
        if (historyRead==null|| historyRead.width != m_Descriptor.width
            || historyRead.height != m_Descriptor.height)
        {
            if (historyBuffer[readindex])
            {
                RenderTexture.ReleaseTemporary(historyBuffer[readindex]);
            }

            historyBuffer[readindex] = RenderTexture.GetTemporary(m_Descriptor.width, m_Descriptor.height, 0);
            historyRead = historyBuffer[readindex];
            m_ResetHistory = true;
            
        }
        historyWrite = historyBuffer[writeindex];
        if (historyWrite == null || historyWrite.width != m_Descriptor.width || historyWrite.height != m_Descriptor.height)
        {
            if (historyBuffer[writeindex])
            {
                RenderTexture.ReleaseTemporary(historyBuffer[writeindex]);
            }
            historyBuffer[writeindex] = RenderTexture.GetTemporary(m_Descriptor.width, m_Descriptor.height, 0);
            historyWrite = historyBuffer[writeindex];

        }
        
    }
    public void Config(RenderTargetIdentifier source,RenderTargetIdentifier target,RenderTargetIdentifier depth)
    {
        _source = source;
        _depth = depth;
        _target = target;
    }
    public override void OnCameraSetup(CommandBuffer cmd, ref VRenderingData renderingData)
    {
       
    }
    public override void Execute(ScriptableRenderContext context, ref VRenderingData renderingData)
    {
        var cmd = CommandBufferPool.Get();
     
        // cmd.SetGlobalTexture("_SourceTex",_source);
        // cmd.Blit(_source,historyWrite,_material,1);
        // cmd.Blit(historyWrite,_source);
        
        cmd.SetGlobalTexture("_SourceTex",_source);
        cmd.SetGlobalTexture("_CameraDepthTex",_depth);
        _material.SetTexture("_HistoryBuffer",historyRead);
        _material.SetInt("_IgnoreHistory",m_ResetHistory ? 1 : 0);
        _material.SetFloat("_BlendAlpha",_BlendAlpha);
        
        // float4x4 _PrevViewProjM_TAA;
        // float4x4 _I_P_Current_jittered;
        _material.SetVector("CurrentOffset",renderingData.ProjectionJitter);
        _material.SetVector("PreviousOffset",renderingData.NextProjectionJitter);
        _material.SetMatrix("_PrevViewProjM_TAA",previousGPUVPMatrix);
        _material.SetMatrix("_I_P_Current_jittered",renderingData.cameraData.Inv_Projection);
        //unity_MatrixInvVP
        //_material.SetMatrix("PreviousViewProjection",previousGPUVPMatrix);
        cmd.Blit(_source,historyWrite,_material,0);
        cmd.Blit(historyWrite,_target);
        m_ResetHistory = false;
        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
        previousGPUVPMatrix = SaveGPUViewProjection(renderingData);
    }
    Matrix4x4 SaveGPUViewProjection(VRenderingData renderingData)
        => GL.GetGPUProjectionMatrix(renderingData.JitteredProjectionMatrix, false) * renderingData.ViewMatrix;
}